
//#define XAssert(s) Assert(s)  
// The above XAssert adds extra (time-consuming) checks
// Using the following line disables these checks.
#define XAssert(s)

#include "Corr2.h"

#ifdef MEMDEBUG
AllocList* allocList;
#endif

std::ostream* dbgout = 0;
bool XDEBUG = false;

int main(int argc, const char* argv[])
{
#ifdef MEMDEBUG
    atexit(&DumpUnfreed);
#endif

    if (argc < 2) {
        std::cerr<<
            "Usage: corree configfile [param=value ...]\n"
            "\tThe first parameter is the configuration file that has \n"
            "\tall the parameters for this run. \n"
            "\tThese values may be modified on the command line by \n"
            "\tentering param/value pais as param=value. \n";
            return 1;
    }

    // Read parameters
    ConfigFile params;
    // These are all the defaults, but might as well be explicit.
    params.setDelimiter("=");
    params.setInclude("+");
    params.setComment("#");
    params.load(argv[1]);
    for(int k=2;k<argc;k++) params.append(argv[k]);

    // Set number of openmp threads if necessary
#ifdef _OPENMP
    if (params.keyExists("omp_num_threads")) {
        int num_threads = params["omp_num_threads"];
        omp_set_num_threads(num_threads);
    }
#endif

    // Setup debugging
    if (params.read("verbose",0) > 0) {
        if (params.read<int>("verbose") > 1) XDEBUG = true;
        if (params.keyExists("debug_file")) {
            std::string debug_file = params["debug_file"];
            dbgout = new std::ofstream(debug_file.c_str());

#ifndef __PGI
            // This gives errors with pgCC, so just skip it.
#ifdef _OPENMP
            // For openmp runs, we use a cool feature known as threadprivate 
            // variables.  
            // In dbg.h, dbgout and XDEBUG are both set to be threadprivate.
            // This means that openmp sets up a separate value for each that
            // persists between threads.  
            // So here, we open a parallel block and initialize each thread's
            // copy of dbgout to be a different file.

            // To use this feature, dynamic threads must be off.  (Otherwise,
            // openmp doesn't know how many copies of each variable to make.)
            omp_set_dynamic(0);

#pragma omp parallel copyin(dbgout, XDEBUG)
            {
                int thread_num = omp_get_thread_num();
                std::stringstream ss;
                ss << thread_num;
                std::string debug_file2 = debug_file + "_" + ss.str();
                if (thread_num > 0) {
                    // This is a memory leak, but a tiny one.
                    dbgout = new std::ofstream(debug_file2.c_str());
                    dbgout->setf(std::ios_base::unitbuf);
                }
            }
#endif
#endif
        } else {
            dbgout = &std::cout;
        }
        dbgout->setf(std::ios_base::unitbuf);
    }

    // Read in all the input files.
    std::vector<boost::shared_ptr<InputFile> > files;
    ReadInputFiles(files,params);
    dbg<<"Read "<<files.size()<<" files.\n";

    // Check that either 1 or 2 files were read in.
    if (files.size() == 0) myerror("No files read in.");
    if (files.size() > 2) myerror("More than 2 files not supported.");

    if (files[0]->useRaDec()) {
        // Construct the object the keeps track of the computed correlation function.
        Corr2<EData,EData,Sphere> corr2(files,params);

        // Process the data to calculate the correlation function
        corr2.process();
        dbg<<"done processing\n";

        // Write the results to the output file(s).
        corr2.write();
    } else {
        // The flat-sky approximation is faster, but of course only accurate for small
        // enough patches.
        Corr2<EData,EData,Flat> corr2(files,params);
        corr2.process();
        dbg<<"done processing\n";
        corr2.write();
    }

    if (dbgout && dbgout != &std::cout) 
    { delete dbgout; dbgout=0; }

    return 0;
}

